package com.tzy.rpc.transport.socket.client;/**
 * @description:
 * @Author HP
 * @create 2022/3/14 16:32
 */

import com.tzy.rpc.entity.RpcRequest;
import com.tzy.rpc.entity.RpcResponse;
import com.tzy.rpc.exception.RpcException;
import com.tzy.rpc.loadbalancer.LoadBalancer;
import com.tzy.rpc.register.NacosServiceDiscovery;
import com.tzy.rpc.register.ServiceDiscovery;
import com.tzy.rpc.serializer.CommonSerializer;
import com.tzy.rpc.transport.RpcClient;
import com.tzy.rpc.transport.socket.util.ObjectReader;
import com.tzy.rpc.transport.socket.util.ObjectWriter;
import com.tzy.rpc.util.RpcMessageChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * @author HP
 * @create 2022-03-14 16:32
 * @desc rpc的客户端
 **/
public class SocketClient implements RpcClient {
    private static final Logger logger = LoggerFactory.getLogger(SocketClient.class);

    private CommonSerializer serializer;
    private ServiceDiscovery serviceDiscovery;

    public SocketClient() {
        this.serviceDiscovery=new NacosServiceDiscovery(null);
    }

    public SocketClient(LoadBalancer loadBalancer) {
        this.serviceDiscovery=new NacosServiceDiscovery(loadBalancer);
    }

    @Override
    public Object sendRequest(RpcRequest rpcRequest) {
        /**
         * socket套接字实现TCP网络传输
         * try()中一般放对资源的申请，若{}出现异常，()资源会自动关闭
         */
        InetSocketAddress inetSocketAddress = serviceDiscovery.lookupService(rpcRequest.getInterfaceName());
        try (Socket socket = new Socket()) {
            socket.connect(inetSocketAddress);
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            ObjectWriter.writeObject(outputStream, rpcRequest, serializer);
            Object obj = ObjectReader.readObject(inputStream);

            RpcResponse rpcResponse = (RpcResponse) obj;
            RpcMessageChecker.check(rpcRequest, rpcResponse);
            return rpcResponse;

        } catch (IOException e) {
            logger.error("调用时有错误发生：" + e);
            throw new RpcException("服务调用失败：", e);
        }
    }

    @Override
    public void setSerializer(CommonSerializer serializer) {
        this.serializer=serializer;
    }
}
